package com.dolphin.common.component.var.enums;

import com.dolphin.common.utils.DateUtils;
import com.dolphin.common.utils.JsonInterface;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shida
 */
@Getter
@ToString
@Slf4j
public enum ValueTypeEnum implements ValueTypeFunction{
    STRING(Integer.valueOf(0), "字符串", String.class, "STRING","keyword", "string"){

        @Override
        public int compareTo(Object realValue, String needValue){
            return (realValue.toString()).compareTo(needValue);
        }

        @Override
        public Boolean lk(Object realValue, String needValue) {
            return realValue.toString().contains(needValue);
        }

        @Override
        public Boolean startAndEnd(Object realValue, List<String> needValues) {
            String tmp = realValue.toString();
            return tmp.startsWith(needValues.get(0)) && tmp.endsWith(needValues.get(1));
        }
    },

    LONG(Integer.valueOf(1), "长整型", Long.class, "LONG","long", "long"){
        @Override
        public int compareTo(Object realValue, String needValue) {
            return ((Long) realValue).compareTo(Long.parseLong(needValue));
        }
    },

    BOOLEAN(Integer.valueOf(2), "布尔类型", Boolean.class, "BOOLEAN", "boolean", "boolean"),
    DATE(Integer.valueOf(4), "日期", Date.class, "DATE", "date", "date"){
        @Override
        public Boolean eq(Object realValue, String needValue) {
            return Objects.equals((Date)realValue, DateUtils.parseDate(needValue, DateUtils.YYYYMMDDHHMMSS));
        }

        @Override
        public int compareTo(Object realValue, String needValue) {
            return ((Date)realValue).compareTo(DateUtils.parseDate(needValue, DateUtils.YYYYMMDDHHMMSS));
        }

        @Override
        public Boolean in(Object realValue, List<String> needValues) {
            return needValues.contains(DateUtils.dateToString((Date) realValue, DateUtils.YYYYMMDDHHMMSS));
        }
    },

    DOUBLE(Integer.valueOf(6), "双精度", Double.class, "DOUBLE", "double", "double"){
        @Override
        public int compareTo(Object realValue, String needValue) {
            return ((Double) realValue).compareTo(Double.parseDouble(needValue));
        }

        @Override
        public Boolean eq(Object realValue, String needValue) {
            return ((Double) realValue).compareTo(Double.parseDouble(needValue)) == 0;
        }

        @Override
        public Boolean in(Object realValue, List<String> needValues) {
            for(String item : needValues){
                if(((Double) realValue).compareTo(Double.parseDouble(item)) == 0){
                    return true;
                }
            }
            return false;
        }
    },

    INT(Integer.valueOf(7), "整型", Integer.class, "INT", "integer", "integer"){
        @Override
        public int compareTo(Object realValue, String needValue) {
            return ((Integer) realValue).compareTo(Integer.parseInt(needValue));
        }
    },

    TIMESTAMP(Integer.valueOf(8), "时间戳", Long.class, "TIMESTAMP", "long", "long"){
        @Override
        public int compareTo(Object realValue, String needValue) {
            return ((Long) realValue).compareTo(Long.parseLong(needValue));
        }
    },

    FLOAT(Integer.valueOf(9), "浮点型", Float.class, "FLOAT", "float", "float"){
        @Override
        public int compareTo(Object realValue, String needValue) {
            return ((Float) realValue).compareTo(Float.parseFloat(needValue));
        }

        @Override
        public Boolean eq(Object realValue, String needValue) {
            return ((Float) realValue).compareTo(Float.parseFloat(needValue)) == 0;
        }

        @Override
        public Boolean in(Object realValue, List<String> needValues) {
            for (String item : needValues){
                if(((Float) realValue).compareTo(Float.parseFloat(item)) == 0){
                    return true;
                }
            }
            return false;
        }
    },

    LIST(Integer.valueOf(10), "列表", List.class, "LIST", null, "list"){
        @Override
        public List<String> intersection(Object realValue, List<String> needValues) {
            if(realValue == null){
                return Collections.emptyList();
            }

            try{
                List<Object> tmp = (List<Object>) realValue;

                return tmp.stream().map(Object::toString).filter(needValues::contains)
                        .collect(Collectors.toList());
            }catch (Exception ex){
                log.error("intersection error,realValue=" + realValue + ", needValues=" + needValues, ex);
            }

            return Collections.emptyList();
        }
    },

    VAR(Integer.valueOf(0), "字符串", String.class, "VAR", null, "string"),
    NUM(Integer.valueOf(1), "数值", Double.class, "NUM", null, "double"),
    AMT(Integer.valueOf(6), "金额", Double.class, "AMT", null,"double"),
    DICTIONARY(Integer.valueOf(7), "字典", List.class, "DICTIONARY",null, "string"),
    MAP(Integer.valueOf(9), "json", Map.class, "MAP", "keyword", "map"),
    ACCOUNT(Integer.valueOf(11), "次数", Integer.class, "ACCOUNT", null, "integer"),
    INTEGER(Integer.valueOf(7),"整型", Integer.class, "INTEGER", "integer", "integer")
    ;

    private Class clazz;
    private Integer id;
    private String description;
    private String type;
    private String esIndexType;
    private String dsaType;

    ValueTypeEnum(Integer id, String description, Class clazz,  String type, String esIndexType, String dsaType) {
        this.clazz = clazz;
        this.id = id;
        this.description = description;
        this.type = type;
        this.esIndexType = esIndexType;
        this.dsaType = dsaType;
    }

    public static ValueTypeEnum getByType(String type){
        if(StringUtils.isEmpty(type)){
            return null;
        }

        for(ValueTypeEnum item : values()){
            if(Objects.equals(item.getType(), type)){
                return item;
            }
        }

        return null;
    }

    public Object toValueByType(Object obj){
        if(obj == null){
            return null;
        }

        String strValue = String.valueOf(obj);
        if("NULL".equalsIgnoreCase(strValue) || "NULL_VAlUE".equalsIgnoreCase(strValue)){
            return null;
        }

        Object ret = null;
        if(clazz.isInstance(obj)){
            ret = obj;
        } else if (String.class == clazz) {
            ret = strValue;
        } else if (Number.class.isAssignableFrom(clazz)) {
            Number tmp = obj instanceof Number ? (Number) obj : new BigDecimal(strValue);

            if(Integer.class == clazz){
                ret = tmp.intValue();
            } else if (Double.class == clazz) {
                ret = tmp.doubleValue();
            } else if (BigDecimal.class == clazz) {
                ret = tmp;
            } else if (Long.class == clazz) {
                ret = tmp.longValue();
            }
        } else if (Boolean.class == clazz) {
            ret = "Y".equals(strValue);
        } else if (Date.class == clazz || Timestamp.class == clazz) {
            Date tmpDate = DateUtils.parseDate(strValue, DateUtils.deterMineDateformatByContent(strValue));
            if(tmpDate != null){
                if(Timestamp.class == clazz){
                    ret = new Timestamp(tmpDate.getTime());
                }else {
                    ret = tmpDate;
                }
            }
        } else if (List.class == clazz) {
            ret = JsonInterface.jsonArr2ListByStr(strValue, Object.class);
        } else if (Map.class == clazz) {
            ret = JsonInterface.jsonObject2Map(strValue);
        }

        return ret;
    }

    public static ValueTypeEnum fromString(String valueType){
        if(valueType == null){
            return null;
        }

        ValueTypeEnum type = null;
        switch (valueType.toUpperCase()){
            case "STRING":
            case "VAR":
            {
                type = ValueTypeEnum.STRING;
                break;
            }
            case "NUM":
            case "AMT":
            case "ACCOUNT":
            {
                type = ValueTypeEnum.NUM;
                break;
            }
            case "BOOLEAN":{
                type = ValueTypeEnum.BOOLEAN;
                break;
            }
            case "LONG":{
                type = ValueTypeEnum.LONG;
                break;
            }
            case "DATE":{
                type = ValueTypeEnum.DATE;
                break;
            }
            case "DOUBLE":{
                type = ValueTypeEnum.DOUBLE;
                break;
            }
            case "INT":{
                type = ValueTypeEnum.INT;
                break;
            }
            case "FLOAT":{
                type = ValueTypeEnum.FLOAT;
                break;
            }
            case "TIMESTAMP":{
                type = ValueTypeEnum.TIMESTAMP;
                break;
            }
            case "MAP":{
                type = ValueTypeEnum.MAP;
                break;
            }
            case "LIST":{
                type = ValueTypeEnum.LIST;
                break;
            }
            default:{
                break;
            }
        }

        return type;
    }
}
